﻿//===========================================================================================================================
// Cuberry - http://www.cuberry.net
// Copyright (c) 2012
// by Peacequare® - Amir Moussa
//===========================================================================================================================
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 
// as published by the Free Software Foundation, either version 3 of the License, or any later version.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// This program is distributed in the hope that it will be useful.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//===========================================================================================================================

using System;
using System.Linq;
using System.Transactions;
using P2.Cuberry.Framework.BOLBase;
using P2.Cuberry.Framework.Helper;
using P2.Cuberry.Framework.Helper.Configuration;
using P2.Cuberry.Framework.Security;
using P2.Cuberry.Modules.SimpleAccounting.FiAccount.DAL;


namespace P2.Cuberry.Modules.SimpleAccounting.FiAccount.BusinessEntities
{
    public class FiAccount : BizObject
    {

        #region Constructors
        
        public FiAccount()
        {
            Modified = false;
        }

                
        public FiAccount(int keyFiAccountID)
        {
            this._fiAccountID = keyFiAccountID;        
            FillMyObject();
            Modified = false;
        }


        public FiAccount(DAL.FiAccount account)
        {        
            Load(account);
        }

        #endregion
     
   
        #region Members
        
        int _fiAccountID = -1;
        public int FiAccountID
        {
            get { return _fiAccountID; }
            protected set
            {
                if (_fiAccountID != value)
                {
                    _fiAccountID = value;
                }
            }
        }
        

        string _fiAccountNo = String.Empty;
        public string FiAccountNo
        {
            get { return _fiAccountNo; }
            set
            {
                if (_fiAccountNo != value)
                {
                    _fiAccountNo = value;
                    Modified = true;
                }
            }
        }


        int _fiAccountFiscalYearID = -1;
        public int FiAccountFiscalYearID
        {
            get { return _fiAccountFiscalYearID; }
            set
            {
                if (_fiAccountFiscalYearID != value)
                {
                    _fiAccountFiscalYearID = value;
                    Modified = true;
                }
            }
        }


        public FiFiscalYear FiscalYear
        {
            get
            {
                return FiFiscalYear.GetItem(this.FiAccountFiscalYearID);
            }
        }


        byte? _fiAccountLevel = null;
        public byte? FiAccountLevel
        {
            get { return _fiAccountLevel; }
            set
            {
                if (_fiAccountLevel != value)
                {
                    _fiAccountLevel = value;
                    Modified = true;
                }
            }
        }


        string _fiAccountNameEn = String.Empty;
        public string FiAccountNameEn
        {
            get { return _fiAccountNameEn; }
            set
            {
                if (_fiAccountNameEn != value)
                {
                    _fiAccountNameEn = value;
                    Modified = true;
                }
            }
        }


        string _fiAccountNameDe = String.Empty;
        public string FiAccountNameDe
        {
            get { return _fiAccountNameDe; }
            set
            {
                if (_fiAccountNameDe != value)
                {
                    _fiAccountNameDe = value;
                    Modified = true;
                }
            }
        }


        string _fiAccountNameAr = String.Empty;
        public string FiAccountNameAr
        {
            get { return _fiAccountNameAr; }
            set
            {
                if (_fiAccountNameAr != value)
                {
                    _fiAccountNameAr = value;
                    Modified = true;
                }
            }
        }


        int _parentFiAccountID = -1;
        public int ParentFiAccountID
        {
            get { return _parentFiAccountID; }
            set
            {
                if (_parentFiAccountID != value)
                {
                    _parentFiAccountID = value;
                    Modified = true;
                }
            }
        }


        int _sortingPosition = -1;
        public int SortingPosition
        {
            get { return _sortingPosition; }
            set
            {
                if (_sortingPosition != value)
                {
                    _sortingPosition = value;
                    Modified = true;
                }
            }
        }


        int _fiAccountTypeID = -1;
        public int FiAccountTypeID
        {
            get { return _fiAccountTypeID; }
            set
            {
                if (_fiAccountTypeID != value)
                {

                    _fiAccountTypeID = value;
                    Modified = true;
                }
            }
        }
        
        public FiAccountType AccountType
        {
            get
            {
                return FiAccountType.GetItem(this.FiAccountTypeID);
            }
        }


        bool? _chargeable = true;
        public bool? Chargeable
        {
            get { return _chargeable; }
            set
            {
                if (_chargeable != value)
                {
                    _chargeable = value;
                    Modified = true;
                }
            }
        }
        

        #endregion


        #region Computed Properties

        public string FiAccountNameCur
        {
            get
            {
                switch (P2Translator.CultureLanguageFU)
                {
                    case "En":
                        {
                            return this.FiAccountNameEn;

                        }
                    case "De":
                        {
                            return this.FiAccountNameDe;

                        }
                    case "Ar":
                        {
                            return this.FiAccountNameAr;

                        }
                    default:
                        return this.FiAccountNameEn;

                }
            }
            set
            {
                switch (P2Translator.CultureLanguageFU)
                {
                    case "En":
                        {
                            this.FiAccountNameEn = value;
                            break;
                        }
                    case "De":
                        {
                            this.FiAccountNameDe = value;
                            break;
                        }
                    case "Ar":
                        {
                            this.FiAccountNameAr = value;
                            break;
                        }
                    default:
                        this.FiAccountNameEn = value;
                        break;
                }
            }
        }


        public string FiAccountFullName
        {
            get
            {
                return String.Format("{0} {1}", FiAccountNo, FiAccountNameCur);
            }
        }


        public FiAccount ParentFiAccount
        {
            get
            {
                if (ParentFiAccountID >= 0)
                {
                    return new FiAccount(ParentFiAccountID);
                }
                else
                {
                    return new FiAccount();
                }
            }
        }


        public string ParentFiAccountFullName
        {
            get
            {
                return this.ParentFiAccount.FiAccountFullName;
            }
        }


        public bool FiFiscalYearEditable
        {
            get
            {
                return StatusID == -1;
            }
        }


        public string FiAccountTypeName
        {
            get
            {
                if (this.AccountType != null)
                    return this.AccountType.FiAccountTypeNameCur;
                else
                    return "";
            }
        }


        public string FiAccountCategoryName
        {
            get
            {
                if (this.AccountType != null)
                    return this.AccountType.FiAccountCategoryNameCur;
                else
                    return "";
            }
        }


        public string FiAccountBalanceTypeName
        {
            get
            {
                if (this.AccountType != null)
                    return this.AccountType.FiAccountBalanceTypeNameCur;
                else
                    return "";
            }
        }


        public string FiAccountPostingTypeName
        {
            get
            {
                if (this.AccountType != null)
                    return this.AccountType.FiAccountPostingTypeNameCur;
                else
                    return "";
            }
        }


        public int FiTransactionCount
        {
            get
            {
                int transactionCount = 0;
                try
                {
                    string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                    using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                    {
                        transactionCount = (from th in db.FiTransactionHeader
                                            join ti in db.FiTransactionItem on th.FiTransactionHeaderID equals ti.FiTransactionHeaderID
                                            where ti.FiAccountID == this.FiAccountID
                                            select th.FiTransactionHeaderID).Distinct().Count();
                    }
                }
                catch (Exception)
                {
                    transactionCount = 0;
                }
                return transactionCount;
            }
        }


        public int FiTransactionOpenCount
        {
            get
            {
                int transactionCount = 0;
                string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                {

                    transactionCount = FiTransactionOpenSubCount(db, this.FiAccountID);
                }
                return transactionCount;
            }
        }


        private int FiTransactionOpenSubCount(FiAccountDataModelDataContext db, int parentAccountID)
        {
            int transactionCount = 0;
            try
            {
                transactionCount = (from th in db.FiTransactionHeader
                                    join ti in db.FiTransactionItem on th.FiTransactionHeaderID equals ti.FiTransactionHeaderID
                                    where ti.FiAccountID == this.FiAccountID
                                    && th.StatusID == 2001
                                    select th.FiTransactionHeaderID).Distinct().Count();

                var subAccounts = from acc in db.FiAccount
                                  where acc.ParentFiAccountID == parentAccountID
                                  select acc;
                foreach (var subAccount in subAccounts)
                {
                    transactionCount += FiTransactionOpenSubCount(db, subAccount.FiAccountID);
                    if (transactionCount > 0)
                        return transactionCount;
                }

            }
            catch (Exception)
            {
                transactionCount = 0;
            }
            return transactionCount;
        }


        public int FiSubAccountCount
        {
            get
            {
                int accountCount = 0;
                string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                {

                    accountCount = (from acc in db.FiAccount
                                    where acc.ParentFiAccountID == this.FiAccountID
                                    select acc).Count();
                }
                return accountCount;
            }
        }


        public bool IsActive
        {
            get
            {
                return (this.StatusID == 1002);
            }
        }

        #endregion


        #region Read Operations
                
        public void Load(int keyFiAccountID)
        {
            FiAccountID = keyFiAccountID;
            if (keyFiAccountID >= 0)
            {
                FillMyObject();
            }
            else
            {
                Load(null);
            }
            Modified = false;
        }


        public void Load(DAL.FiAccount account)
        {
            if (account != null)
            {
                this.FiAccountID = account.FiAccountID;
                this.FiAccountNo = account.FiAccountNo;
                this.FiAccountFiscalYearID = account.FiAccountFiscalYearID;
                this.FiAccountLevel = account.FiAccountLevel.GetValueOrDefault(1);
                this.FiAccountNameEn = account.FiAccountNameEn;
                this.FiAccountNameDe = account.FiAccountNameDe;
                this.FiAccountNameAr = account.FiAccountNameAr;
                this.ParentFiAccountID = account.ParentFiAccountID.GetValueOrDefault(-1);
                this.SortingPosition = account.SortingPosition.GetValueOrDefault(-1);
                this.FiAccountTypeID = account.FiAccountTypeID.GetValueOrDefault(-1);
                this.Chargeable = account.Chargeable;

                //Default Fields                
                this.CreatedBy = account.CreatedBy;
                this.CreatedOn = account.CreatedOn;
                this.EditedBy = account.EditedBy;
                this.EditedOn = account.EditedOn;
                this.Timestamp = account.TStamp;
                this.StatusID = account.StatusID.GetValueOrDefault(P2.Cuberry.Framework.Helper.Workflows.WorkflowStatus.GetInitialStatus(this.EntityName).StatusID);
            }
            else
            {
                FiAccountFiscalYearID = -1;
                FiAccountLevel = null;
                FiAccountNo = String.Empty;
                FiAccountNameEn = String.Empty;
                FiAccountNameDe = String.Empty;
                FiAccountNameAr = String.Empty;
                ParentFiAccountID = -1;
                SortingPosition = -1;
                FiAccountTypeID = -1;
                Chargeable = true;

                //Default Fields
                this.CreatedBy = String.Empty;
                this.EditedBy = String.Empty;
                P2.Cuberry.Framework.Helper.Workflows.WorkflowStatus initStatus = P2.Cuberry.Framework.Helper.Workflows.WorkflowStatus.GetInitialStatus(this.EntityName);
                this.StatusID = initStatus.StatusID;
            }
            Modified = false;
        }


        protected P2TransactionMessage FillMyObject()
        {
            P2TransactionMessage tMsg = new P2TransactionMessage();

            if (this._fiAccountID < 0)
            {
                Load(this._fiAccountID);
                return tMsg;
            }

            try
            {
                string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                {
                    var accounts = from acc in db.FiAccount
                                   where acc.FiAccountID == this._fiAccountID
                                   select acc;

                    foreach (var account in accounts)
                    {
                        Load(account);
                    }
                }

                tMsg.TransactionStatus = "green";
                tMsg.MessageText = "TMsg_FillMyObjectSuceeded";
            }
            catch (Exception ex)
            {
                tMsg.TransactionStatus = "red";
                tMsg.MessageText = "Error_Error";
                tMsg.MessageFreeText = ex.Message;
                P2ExceptionHandler.LogException(ex, this);
            }          

            return tMsg;
        }


        public int GetLastChildSortingPosition()
        {
            string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
            using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
            {
                var maxPosition = (from acc in db.FiAccount
                                   where acc.ParentFiAccountID == this._fiAccountID
                                   select acc.SortingPosition).Max();
                return maxPosition.GetValueOrDefault(0);

            }
        }


        public static FiAccount GetFiAccountByAccountNo(string fiAccountNo, int fiAccountFiscalYearID)
        {
            string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
            using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
            {

                var accounts = from acc in db.FiAccount
                               where acc.FiAccountNo == fiAccountNo
                               && acc.FiAccountFiscalYearID == fiAccountFiscalYearID
                               select acc;

                if (accounts != null && accounts.Count() > 0)
                {
                    var account = accounts.First();
                    return new FiAccount(account);
                }
                else
                    return null;
            }
        }

        #endregion


        #region Update Operations

        public P2MessageStack InsertAndUpdate(P2MessageStack MessageStack, bool checkDoublicate)
        {
            MessageStack.AddRange(this.Validator.Validate(this));

            try
            {
                if (this.FiAccountID < 0 && (FiscalYear.StatusID == 173103 || FiscalYear.StatusID == 173104))
                {
                    MessageStack.Add(new P2TransactionMessage("red", P2Translator.GetResource("TMsg_FiscalYearStatusError")));
                }
                
                if (MessageStack.StatusMessage.MessageStatus == P2ValidationStatus.green || MessageStack.StatusMessage.MessageStatus == P2ValidationStatus.white || (MessageStack.StatusMessage.MessageStatus == P2ValidationStatus.yellow && P2Validator.YellowErrorDialog.AskSave(MessageStack)))
                {
                    MessageStack.Clear();
                    string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                    using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                    {
                        using (TransactionScope ts = new TransactionScope())
                        {
                            if (this.StatusID == -1) this.StatusID = 1001;
                            DAL.FiAccount editedItem;

                            if (this.FiAccountID < 0)
                            {
                                editedItem = new DAL.FiAccount()
                                {
                                    FiAccountNo = this.FiAccountNo,
                                    FiAccountFiscalYearID = this.FiAccountFiscalYearID,
                                    FiAccountLevel = this.FiAccountLevel,
                                    FiAccountNameEn = this.FiAccountNameEn,
                                    FiAccountNameDe = this.FiAccountNameDe,
                                    FiAccountNameAr = this.FiAccountNameAr,
                                    ParentFiAccountID = this.ParentFiAccountID,
                                    SortingPosition = this.SortingPosition,
                                    FiAccountTypeID = this.FiAccountTypeID,
                                    Chargeable = this.Chargeable, 
                                   
                                    //Default Fields
                                    CreatedBy = User.Current.UserID,
                                    CreatedOn = DateTime.Now,
                                    EditedBy = User.Current.UserID,
                                    EditedOn = DateTime.Now,
                                    StatusID = this.StatusID
                                };
                                db.AddToFiAccount(editedItem);
                            }
                            else
                            {
                                editedItem = (from acc in db.FiAccount
                                              where acc.FiAccountID == this.FiAccountID
                                              select acc).First();

                                if (editedItem.TStamp == this.Timestamp)
                                {
                                    editedItem.FiAccountNo = this.FiAccountNo;
                                    editedItem.FiAccountFiscalYearID = this.FiAccountFiscalYearID;
                                    editedItem.FiAccountLevel = this.FiAccountLevel;
                                    editedItem.FiAccountNameEn = this.FiAccountNameEn;
                                    editedItem.FiAccountNameDe = this.FiAccountNameDe;
                                    editedItem.FiAccountNameAr = this.FiAccountNameAr;
                                    editedItem.ParentFiAccountID = this.ParentFiAccountID;
                                    editedItem.SortingPosition = this.SortingPosition;
                                    editedItem.FiAccountTypeID = this.FiAccountTypeID;
                                    editedItem.Chargeable = this.Chargeable;

                                    //Default Fields
                                    editedItem.EditedBy = User.Current.UserID;
                                    editedItem.EditedOn = DateTime.Now;
                                    editedItem.StatusID = this.StatusID;

                                    //track changes!
                                    this.SaveChangeLog(this.FiAccountID);
                                }
                                else
                                {                                    
                                    MessageStack.Add(new P2TransactionMessage("red", P2Translator.GetResource("TMsg_AccountNotUpdated")));
                                }
                            }
                            if (MessageStack.StatusMessage.MessageStatus != P2ValidationStatus.red)
                            {
                                db.SaveChanges();
                                ts.Complete();
                                if (this.FiAccountID < 0)
                                {
                                    MessageStack.Add(new P2TransactionMessage("green", P2Translator.GetResource("TMsg_AccountAdded")));
                                    this.FiAccountID = editedItem.FiAccountID;
                                }
                                else
                                    MessageStack.Add(new P2TransactionMessage("green", P2Translator.GetResource("TMsg_AccountUpdated")));
                            }
                        }
                    }
                    Modified = false;
                    FillMyObject();
                }
            }
            catch (Exception ex)//AM:TC!!
            {
                MessageStack.Add(new P2TransactionMessage("red", P2Translator.GetResource("Error_Error")));
                P2ExceptionHandler.LogException(ex, this);
            }
            return MessageStack;
        }


        public void UpdateChargeable()
        {
            string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
            using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
            {
                var account = (from acc in db.FiAccount
                               where acc.FiAccountID == this._fiAccountID
                               select acc).First();
                account.Chargeable = this.Chargeable;
                db.SaveChanges();
            }
            this.FillMyObject();
        }


        public void MoveUpDown(bool moveUp)
        {
            try
            {
                string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                {
                    var accounts = from acc in db.FiAccount
                                   where acc.ParentFiAccountID == this.ParentFiAccountID
                                   orderby acc.SortingPosition
                                   select acc;
                    DAL.FiAccount prevAccount = null, thisAccount = null, nextAccount = null;
                    foreach (var account in accounts)
                    {
                        if (account.FiAccountID == this._fiAccountID)
                        {
                            thisAccount = account;
                        }
                        else
                        {
                            if (thisAccount != null)
                            {
                                nextAccount = account;
                                break;
                            }
                            else
                                prevAccount = account;
                        }
                    }
                    if (!moveUp)
                    {
                        if (thisAccount != null && nextAccount != null)
                        {
                            int? tempPos = thisAccount.SortingPosition;
                            thisAccount.SortingPosition = nextAccount.SortingPosition;
                            nextAccount.SortingPosition = tempPos;
                        }
                    }
                    else
                    {
                        if (thisAccount != null && prevAccount != null)
                        {
                            int? tempPos = thisAccount.SortingPosition;
                            thisAccount.SortingPosition = prevAccount.SortingPosition;
                            prevAccount.SortingPosition = tempPos;
                        }
                    }

                    db.SaveChanges();
                }
                this.FillMyObject();
            }
            catch (Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
            }
        }


        public void Lock()
        {
            try
            {
                string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                {
                    using (TransactionScope ts = new TransactionScope())
                    {

                        var account = (from acc in db.FiAccount
                                       where acc.FiAccountID == this.FiAccountID
                                       select acc).First();

                        account.StatusID = 1003;
                        LockSubAccounts(db, this.FiAccountID);
                        db.SaveChanges();
                        ts.Complete();
                    }
                }
                this.FillMyObject();
            }
            catch (Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
            }
        }


        private static void LockSubAccounts(FiAccountDataModelDataContext db, int parentFiAccountID)
        {
            try
            {
                var accounts = from acc in db.FiAccount
                               where acc.ParentFiAccountID == parentFiAccountID
                               select acc;
                foreach (var account in accounts)
                {
                    LockSubAccounts(db, account.FiAccountID);
                    account.StatusID = 1003;
                }
            }
            catch (Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", "FiAccount", System.Reflection.MethodInfo.GetCurrentMethod().Name));
            }
        }


        public bool Delete()
        {
            try
            {
                if (this.FiAccountID > -1)
                {
                    string connectionString = ConfigurationSetUp.GetEntConnectionString("Business", Properties.Settings.Default.EntityResources);
                    using (FiAccountDataModelDataContext db = new FiAccountDataModelDataContext(connectionString))
                    {
                        try
                        {
                            var account = (from acc in db.FiAccount
                                           where acc.FiAccountID == this._fiAccountID
                                           select acc).First();
                            db.DeleteObject(account);
                            db.SaveChanges();
                            return true;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex) //AM:TC
            {
                P2ExceptionHandler.LogException(ex, string.Format("{0}.{1}", this.GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name));
                return false;
            }
        }

        #endregion


        #region Validator

        public override P2Validator Validator
        {
            get
            {
                if (_validator == null)
                    _validator = new P2Validator(Properties.Settings.Default.ModuleName, this.EntityName, "FiAccountID", this);
                return _validator;
            }
        }

        #endregion
    }
}
